<template>
  <div class="digital-human">
    <!-- 图片元素 -->
    <div class="image-container">
      <img :src="currentFrame" class="frame-image" alt=""/>
    </div>

    <!-- 音频控件 -->
    <audio id="audioElementId" ref="audioElement"></audio>


    <audio id="audioElementId2" ref="audioElement2"></audio>

    <!-- 输入框和提交按钮 -->
    <div class="input-section">
      <input v-model="userInput" type="text" placeholder="请输入内容" class="input-box"/>
      <button @click="handleSubmit" class="submit-button" :disabled="isSubmitting">提交</button>
    </div>

    <div ref="linkSection" class="link-section" v-show="isLinkVisible">
      <div v-for="(url, index) in urls" :key="index">
        链接地址: <a :href="url" class="link">{{ url }}</a>
      </div>
    </div>
    <div class="error-message" v-if="errorMessage">{{ errorMessage }}</div>
    <div class="error-message" v-if="errorMessage2">{{ errorMessage2 }}</div>
  </div>
</template>


<script>
import {onMounted, ref} from 'vue';
import axios from 'axios';

export default {
  setup() {
    const loadedImages = ref([]) // 进入页面提前将图片换成到本地
    const userInput = ref('');
    const audioElement = ref(null); // 音频元素的引用
    const audioElement2 = ref(null);
    const isSubmitting = ref(false);
    const errorMessage = ref('');
    const errorMessage2 = ref('');
    const isLinkVisible = ref(false);
    const urls = ref([]);
    const currentFrame = ref(''); // 当前显示的帧图片
    const frameIndex = ref(1); // 当前帧的索引
    let frameInterval = null; // 用于控制帧动画的定时器

    const totalFrames = 30; // 总帧数
    const framePathTemplate = "https://assets-service.obs.cn-south-1.myhuaweicloud.com/ImageHuman/1717658488515_3480_"; // 图片路径模板

    // 换成图片到本地
    const preloadImages = async () => {
      isSubmitting.value = true;
      errorMessage.value = '我正在初始化图片;'
      const imagePromises = [];
      for (let i = 1; i <= totalFrames; i++) {
        const frameNumber = String(i).padStart(6, '0'); // 补全位数到6位
        const imageUrl = `${framePathTemplate}${frameNumber}.png?x-image-process=image/resize,p_100`; // 当前图片的 URL
        // 将每个图片的加载 Promise 添加到数组中
        imagePromises.push(
            fetch(imageUrl)
                .then(response => {
                  if (!response.ok) throw new Error('网络响应不正常');
                  return response.blob(); // 获取图片的 Blob
                })
                .then(blob => {
                  const url = URL.createObjectURL(blob); // 创建一个临时的 URL
                  loadedImages.value[i] = url; // 将图片 URL 存储到 loadedImages 数组
                })
                .catch(error => {
                  console.error('预加载失败:', error);
                })
        );
      }
      await Promise.all(imagePromises); // 等待所有图片加载完
      isSubmitting.value = false;
      errorMessage.value = '我初始化图片完毕;'
    }

    // 处理音频播放完毕的逻辑
    const handleAudioEnded = () => {
      errorMessage.value = '我执行了处理音频播放完毕的逻辑'
      stopAnimation();
      imageIni();
    };

    // const handleAudioEnded2 = () => {
    //   errorMessage2.value = '我执行了处理音频2播放完毕的逻辑'
    // };

    // 更新当前帧的函数
    const updateFrame = () => {
      if (frameIndex.value > totalFrames) {
        frameIndex.value = 1; // 重置到第一帧
      }
      currentFrame.value = loadedImages.value[frameIndex.value]; // 使用已加载的图片
      frameIndex.value++;
    };

    // 启动帧动画
    const startAnimation = () => {
      if (!frameInterval) {
        frameInterval = setInterval(updateFrame, 100); // 每100ms更新一帧
      }
    };

    // 停止帧动画
    const stopAnimation = () => {
      console.log(frameInterval)
      if (frameInterval) {
        clearInterval(frameInterval);
        frameInterval = null;
      } else {
        errorMessage.value = '我停止帧动画没有成功'
      }
    };

    // 输入提交处理
    const handleSubmit = async () => {
      if (userInput.value) {
        // audioElement2.value.src = `http://music.163.com/song/media/outer/url?id=317151.mp3`;
        // audioElement2.value.play().then(() => {
        //   errorMessage2.value = '我播放了音频2';
        //   console.log('Audio started playing');
        // }).catch((error) => {
        //   errorMessage2.value = `我播放了音频2出现了异常${error}`;
        //   console.error('Audio playback error:', error);
        // });
        try {
          isSubmitting.value = true;
          errorMessage.value = '';

          await testToAudio(userInput.value);
        } catch (error) {
          console.error('请求出错:', error);
          errorMessage.value = '请求失败，请稍后重试。';
        } finally {
          userInput.value = '';
          isSubmitting.value = false;
        }
      }
    };


    const fetchAudioAsBase64 = async (url) => {
      const response = await fetch(url);
      const arrayBuffer = await response.arrayBuffer();
      const base64Audio = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
      console.log(`转换的base64格式:${base64Audio}`)
      return base64Audio;
    }

    const base64ToArrayBuffer = (base64) => {
      const binaryString = atob(base64);
      const len = binaryString.length;
      const bytes = new Uint8Array(len);
      for (let i = 0; i < len; i++) {
        bytes[i] = binaryString.charCodeAt(i);
      }
      return bytes.buffer;
    };

    const base64ToBlob = (base64, fileType) => {
      let typeHeader = 'data:application/' + fileType + ';base64,'; // 定义base64 头部文件类型
      let audioSrc = typeHeader + base64; // 拼接最终的base64
      let arr = audioSrc.split(',');
      let array = arr[0].match(/:(.*?);/);
      let mime = (array && array.length > 1 ? array[1] : fileType) || fileType;
      // 去掉url的头，并转化为byte
      let bytes = window.atob(arr[1]);
      // 处理异常,将ascii码小于0的转换为大于0
      let ab = new ArrayBuffer(bytes.length);
      // 生成视图（直接针对内存）：8位无符号整数，长度1个字节
      let ia = new Uint8Array(ab);
      for (let i = 0; i < bytes.length; i++) {
        ia[i] = bytes.charCodeAt(i);
      }
      return new Blob([ab], {
        type: mime
      });
    }

    // 音频处理函数
    const testToAudio = async (message) => {
      // 将文本翻译为语音
      const audioResponse = await axios.post('https://test-wd-api.iwanshang.cloud/kma/gpt/audio/text2Audio', {
        text: message, // 将翻译后的文本发送到服务器
        audio_format: 'mp3'
      });

      console.log('语音数据:', audioResponse.data);
      if (audioResponse.data.code === 200 && audioResponse.data.audio) {
        const base64Audio = audioResponse.data.audio; // 修正为从 audioResponse 中获取 audio 数据
        // 设置音频元素的 src 属性并播放
        const arrayBuffer = base64ToArrayBuffer(base64Audio);
        const blob = new Blob([arrayBuffer], {type: 'audio/mp3'});
        //const blob = base64ToBlob(base64Audio,"mp3");
        const url = URL.createObjectURL(blob);
        audioElement.value.src = url;
        audioElement.value.play().then(() => {
          errorMessage.value = `我播放了音频,生成的url为${url}`;
          startAnimation();
          console.log('Audio started playing');
        }).catch((error) => {
          errorMessage.value = `我播放了音频出现了异常${error},生成的url为${url}`;
          console.error('Audio playback error:', error);
        });
      } else {
        console.error('未能获取到有效的音频数据');
      }
    }

    onMounted(async () => {
      await preloadImages();
      await imageIni();
      if (audioElement.value) {
        console.log('Audio element found:', audioElement.value);
        errorMessage2.value = '音频元素已找到';
        // audioElement.value.addEventListener('ended', () => {
        //   handleAudioEnded();
        // });
        document.getElementById('audioElementId').addEventListener('ended', function () {
          handleAudioEnded();
        });
        // document.getElementById('audioElementId2').addEventListener('ended', function () {
        //   handleAudioEnded2();
        // });
      } else {
        console.error('Audio element not found');
        errorMessage2.value = '音频元素未找到';
      }
    });

    const imageIni = () => {
      console.log('初始化')
      frameIndex.value = 1;
      const frameNumber = String(frameIndex.value).padStart(6, '0'); // 补全位数到6位
      currentFrame.value = `${framePathTemplate}${frameNumber}.png`;
    }

    return {
      userInput,
      isSubmitting,
      errorMessage,
      errorMessage2,
      currentFrame,
      isLinkVisible,
      base64ToArrayBuffer,
      base64ToBlob,
      urls,
      handleSubmit,
      audioElement,
      audioElement2,
      imageIni,
      fetchAudioAsBase64
    };
  },
};
</script>


<style scoped>


.error-message {
  color: red;
  font-size: 1rem;
  margin-top: 10px;
}

.digital-human {
  position: relative;
  width: 90vw;
  max-width: 360px;
  height: 60vh;
  max-height: 640px;
  background: transparent;
  transition: transform 0.3s ease-in-out, box-shadow 0.3s ease-in-out;
}

.image-container {
  /* 确保父元素没有背景 */
  background-color: transparent; /* 可选 */
  /* 其他样式 */
}

.frame-image {
  background-color: transparent;
}

.input-box {
  padding: 10px;
  margin-bottom: 10px;
  width: 100%;
  max-width: 300px;
  border-radius: 5px;
  border: 1px solid #ccc;
}

.submit-button {
  padding: 10px 20px;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.submit-button:hover {
  background-color: #0056b3;
}

.link-section {
  margin-top: 20px;
}

.link {
  color: #3498db;
  font-size: 1.2rem;
  text-decoration: none;
  font-weight: bold;
}

.link:hover {
  color: #2980b9;
  text-decoration: underline;
}
</style>


